﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.VirtualEarth.MapControl;
using System.Windows.Media.Imaging;
using GraphDrawer.GraphProvider;

namespace GraphDrawer {
	public partial class VirtualEarthControl : UserControl, GraphLayout.Interface.IGraph {
		String token = "12";
		GraphProviderServiceSoapClient cl = new GraphProviderServiceSoapClient();
		GraphLayout.GraphRepresentation.Graph gg;
		private Graph m_graph;

		static Simulation simulationPage;

		public VirtualEarthControl(Simulation simulationPage) {
			InitializeComponent();
			VirtualEarthControl.simulationPage = simulationPage;
			cl.StartSimulationCompleted += new EventHandler<StartSimulationCompletedEventArgs>(soapClient_StartSimulationCompleted);
			cl.GetGeoCodeCompleted += new EventHandler<GetGeoCodeCompletedEventArgs>(soapClient_GetGeoCodeCompleted);
			cl.StartSimulationAsync(simulationPage.GetSetup().SimulationSetup, token);
			OldElements += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(VirtualEarthControl_OldElements);
			NewEdges += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(VirtualEarthControl_NewEdges);
			LayoutRoot.SizeChanged += new SizeChangedEventHandler(LayoutRoot_SizeChanged);
		}

		void VirtualEarthControl_NewEdges(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
			switch (e.Action) {
				case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
					foreach (GraphLayout.GraphRepresentation.EdgeItem item in e.NewItems) {
						var line = prefuse.action.layout.Layout.DrawLine(item.Source.X + ((GraphLayout.GraphRepresentation.NodeItem)item.Source).Width / 2,
								item.Source.Y + ((GraphLayout.GraphRepresentation.NodeItem)item.Source).Height / 2,
								item.Target.X + ((GraphLayout.GraphRepresentation.NodeItem)item.Target).Width / 2,
								item.Target.Y + ((GraphLayout.GraphRepresentation.NodeItem)item.Target).Height / 2);

						item.VisualLine = line;
						item.Children.Add(line);


						item.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.Location(line.X1, line.Y1));
						item.SetValue(MapLayer.MapPositionMethodProperty, PositionMethod.Center);

						//item.SetValue(Canvas.ZIndexProperty, -10);
						//this.Children.Add(item);
					}
					break;
				case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
					foreach (GraphLayout.GraphRepresentation.EdgeItem item in e.OldItems) {
						(Map.FindName("PushpinLayer") as MapLayer).RemoveChild(item);
					}
					break;
				case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
					break;
				case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
					break;
				default:
					break;
			}
		}

		void VirtualEarthControl_OldElements(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {

		}

		void soapClient_GetGeoCodeCompleted(object sender, GetGeoCodeCompletedEventArgs e) {
			Double latitude = e.Result[0];
			Double longitude = e.Result[1];
			AddPushpin(latitude, longitude, (GraphElement)e.UserState);
			var item = (GraphElement)e.UserState;
			PairKeyValue p1 = new PairKeyValue();
			p1.Key = "locationX";
			p1.Value = latitude.ToString();
			PairKeyValue p2 = new PairKeyValue();
			p2.Key = "locationY";
			p2.Value = longitude.ToString();
			item.Keys.Add(p1);
			item.Keys.Add(p2);
		}

		void soapClient_StartSimulationCompleted(object sender, StartSimulationCompletedEventArgs e) {
			m_graph = e.Result;
			simulationPage.map.Clear();

			gg = new GraphLayout.GraphRepresentation.Graph();
			gg.NewEdges += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(gg_NewEdges);
			gg.OldElements += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(gg_OldElements);
			gg.Nodes = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.Interface.VisualItem>();
			gg.Edges = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem>();

			foreach (var item in m_graph.Vertices) {
				double? latitude = null;
				double? longitude = null;
				bool noPushpin = false;
				foreach (var key in item.Keys) {
					if (key.Key == "locationX") {
						latitude = Convert.ToDouble(key.Value, System.Globalization.NumberFormatInfo.InvariantInfo);
					}
					if (key.Key == "locationY") {
						longitude = Convert.ToDouble(key.Value, System.Globalization.NumberFormatInfo.InvariantInfo);
					}

					if (latitude.HasValue && longitude.HasValue && !noPushpin) {
						AddPushpin(latitude.Value, longitude.Value, item);
						noPushpin = true;
					}

				}
				if (!latitude.HasValue && !longitude.HasValue) {
					foreach (var key in item.Keys) {
						if (key.Key == "location") {
							cl.GetGeoCodeAsync(key.Value, item);
							break;
						}
					}
				}


			}

			if (simulationPage.map.Count < m_graph.Vertices.Count)
				return;

			foreach (var item in m_graph.Edges) {
				var n1 = (from v in m_graph.Vertices
						  where v.Id == item.Source
						  select v).First();
				var n2 = (from v in m_graph.Vertices
						  where v.Id == item.Target
						  select v).First();

				GraphLayout.GraphRepresentation.EdgeItem e1 = new GraphLayout.GraphRepresentation.EdgeItem();
				e1.Target = simulationPage.map[n2];
				e1.Source = simulationPage.map[n1];
				e1.Graph = gg;

				//gg.Edges.Add(e1);

				var line = prefuse.action.layout.Layout.DrawLine(
						(e1.Source.Element as GraphElement).x,
						(e1.Source.Element as GraphElement).y,
						(e1.Target.Element as GraphElement).x,
						(e1.Target.Element as GraphElement).y);


				e1.VisualLine = line;
				e1.Children.Add(line);

				//e1.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.Location(line.X1, line.Y1));
				/*e1.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.MapPolyline() {
					Locations = new LocationCollection() {
						new Location(line.X1, line.Y1),
						new Location(line.X2, line.Y2)
					}
				});*/
				e1.SetValue(MapLayer.MapPositionMethodProperty, PositionMethod.Center);

				e1.SetValue(Canvas.ZIndexProperty, -10);

				//(Map.FindName("PushpinLayer") as MapLayer).AddChild(e1);
				(Map.FindName("PushpinLayer") as MapLayer).AddChild(
					new Microsoft.VirtualEarth.MapControl.MapPolyline() {
						Locations = new LocationCollection() {
							new Location(line.X1, line.Y1),
							new Location(line.X2, line.Y2)
						},
						Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)),
						StrokeThickness = 1.0,
					}
				);
			}

		}

		void gg_NewEdges(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {

		}

		void gg_OldElements(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {

		}

		private void AddPushpin(double latitude, double longitude, GraphElement elem) {
			var node = (GraphLayout.GraphRepresentation.NodeItem)GleeGraphDrawer.CreateNodeCanvas(elem, simulationPage);

			gg.Nodes.Add(node);
			((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).Graph = gg;
			gg.Nodes.Last().Element = elem;
			elem.x = latitude;
			elem.y = longitude;

			((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseEnter += new MouseEventHandler(GleeGraphDrawer.SetInfoPanel);
			((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseLeave += new MouseEventHandler(GleeGraphDrawer.ResetInfoPanel);
			((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).NodeSelected += new MouseEventHandler(nodeCanvas_NodeSelected);

			node.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.Location(latitude, longitude));
			node.SetValue(MapLayer.MapPositionMethodProperty, PositionMethod.Center);

			simulationPage.map.Add(elem, node);

			(Map.FindName("PushpinLayer") as MapLayer).AddChild(node);
		}

		void nodeCanvas_NodeSelected(object sender, MouseEventArgs e) {
			var curr = sender as GraphLayout.GraphRepresentation.NodeItem;
			var prev = curr.Graph.PreviousSelectedNode as GraphLayout.GraphRepresentation.NodeItem;

			if (prev != null) {
				GraphElement n = prev.Element as GraphElement;

				String text = String.Empty;
				foreach (var description in n.Keys) {
					if (description.Key == "stateName") {
						text = description.Value;
						break;
					}
				}

				((Ellipse)prev.Children[0]).Fill = simulationPage.GetColorForDisease(text);
				((Ellipse)prev.Children[0]).Stroke = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));
				((Ellipse)prev.Children[0]).StrokeThickness = 1.0;
			}
			if (curr != null) {
				GraphElement n = curr.Element as GraphElement;

				var ditails = (Map.FindName("ditails") as PatientDetails);
				ditails.UpdateDetails(n.Keys);



				((Ellipse)curr.Children[0]).Fill = new SolidColorBrush(Color.FromArgb(128, 55, 55, 100));
				((Ellipse)curr.Children[0]).Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
				((Ellipse)curr.Children[0]).StrokeThickness = 2.0;
			}
		}

		void LayoutRoot_SizeChanged(object sender, SizeChangedEventArgs e) {
			Map.Width = e.NewSize.Width;
			Map.Height = e.NewSize.Height;
		}

		#region IGraph Members

		public event System.Collections.Specialized.NotifyCollectionChangedEventHandler NewEdges;

		public event System.Collections.Specialized.NotifyCollectionChangedEventHandler OldElements;

		public System.Collections.ObjectModel.ObservableCollection<GraphLayout.Interface.VisualItem> Nodes {
			get {
				return gg.Nodes;
			}
		}

		public System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem> Edges {
			get {
				return gg.Edges;
			}
		}

		public GraphLayout.Interface.VisualItem SelectedNode {
			get {
				//throw new NotImplementedException();
				return gg.Nodes[1];
			}
			set {
				//throw new NotImplementedException();
			}
		}

		public GraphLayout.Interface.VisualItem PreviousSelectedNode {
			get {
				//throw new NotImplementedException();
				return gg.Nodes[0];
			}
			set {
				//throw new NotImplementedException();
			}
		}

		#endregion
	}
}
